﻿ using System;
using System.Collections.Generic;
using WiMo.Games.Audio;
using WiMo.Games.Drawables;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;

namespace WiMo.Games.WM5
{
    public class ContentManager : IContentManager
    {
        private int _dpi;

        private Dictionary<string, Bitmap> _assetLibrary = new Dictionary<string, Bitmap>();

        public ContentManager(IGameEngine engine)
        {
            AssetFactory = engine.AssetFactory;
            Engine = engine;

            var tempBitmap = new Bitmap(64, 64);
            var gr = Graphics.FromImage(tempBitmap);
            _dpi = Convert.ToInt32(gr.DpiX);
            gr.Dispose();
            tempBitmap.Dispose();

        }

        public IGameEngine Engine
        {
            get;
            set;
        }

        public ISpriteFont GetFont(string name)
        {
            return new SpriteFont();
        }

        public string GetFullPath(string name)
        {
            var currentDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);

            return string.Format(@"{0}\{1}\{2}", currentDirectory, ContentLocation, name);
        }

        private ITexture LoadTexture(string name)
        {
            if (_assetLibrary.ContainsKey(name))
            {
                System.Diagnostics.Debug.WriteLine("Loading cached resource.");
                return new Texture { TextureInformation = _assetLibrary[name] };
            }

            ITexture texture = null;

            if (Engine.Display.ScaleFactor.X == 2.0f || Engine.Display.ScaleFactor.Y == 2.0f)
                texture = LoadTextureFromResourceDPISpecific(name);

            if (texture == null)
            {
                texture = LoadTextureFromResourceWMSpecific(name);
            }

            if (texture == null)
            {
                texture = LoadTextureFromResource(name);
                if(texture == null)
                    texture = LoadTextureFromFile(name);
            }

            if (texture != null)
            {
                _assetLibrary.Add(name, texture.TextureInformation as Bitmap);
                var bm = (texture.TextureInformation as Bitmap);
                //bm.LockBits(new System.Drawing.Rectangle(0, 0, bm.Size.Width, bm.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppRgb565);
            }

            return texture;
        }

        private ITexture LoadTextureFromResourceDPISpecific(string name)
        {
            if (!name.StartsWith("/"))
                name = String.Format("/{0}", name);

            var assembly = Engine.Game.GetType().Assembly;
            var path = String.Format("{0}.{1}._{2}{3}", assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')), ContentLocation, _dpi, name.Replace("/", "."));
            using (var _imageStream = assembly.GetManifestResourceStream(path))
            {
                if (_imageStream == null)
                    return null;

                return new Texture { TextureInformation = new Bitmap(_imageStream) };
            }
        }

        private ITexture LoadTextureFromResourceWMSpecific(string name)
        {
            if (!name.StartsWith("/"))
                name = String.Format("/{0}", name);

            var assembly = Engine.Game.GetType().Assembly;
            var path = String.Format("{0}.{1}.{2}{3}", assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')), ContentLocation, "wm", name.Replace("/", "."));
            using (var _imageStream = assembly.GetManifestResourceStream(path))
            {
                if (_imageStream == null)
                    return null;

                return new Texture { TextureInformation = new Bitmap(_imageStream) };
            }
        }

        private ITexture LoadTextureFromResource(string name)
        {
            if (!name.StartsWith("/"))
                name = String.Format("/{0}", name);

            var assembly = Engine.Game.GetType().Assembly;
            var path = String.Format("{0}.{1}{2}", assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')), ContentLocation, name.Replace("/", "."));
            using (var _imageStream = assembly.GetManifestResourceStream(path))
            {
                if (_imageStream == null)
                    return null;

                Bitmap loadedBm = new Bitmap(_imageStream);

                return ScaleTexture(loadedBm);
            }
        }

        private ITexture LoadTextureFromFile(string name)
        {
            string filePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
            if (!String.IsNullOrEmpty(ContentLocation))
                filePath += Path.DirectorySeparatorChar + ContentLocation;
            filePath += Path.DirectorySeparatorChar + name;

            if (!System.IO.File.Exists(filePath))
                return null;

            var loadedBm = new Bitmap(filePath);

            return ScaleTexture(loadedBm);
        }

        private ITexture ScaleTexture(Bitmap loadedBm)
        {
            if (Engine.Display.ScaleFactor != Vector2.One)
            {
                var scaledSize = new Size((int)(loadedBm.Size.Width * Engine.Display.ScaleFactor.X), (int)(loadedBm.Size.Height * Engine.Display.ScaleFactor.Y));

                var scaledBitmap = new Bitmap(scaledSize.Width, scaledSize.Height);

                using (Graphics gr = Graphics.FromImage(scaledBitmap))
                {
                    gr.DrawImage(loadedBm, new System.Drawing.Rectangle(0, 0, scaledSize.Width, scaledSize.Height), new System.Drawing.Rectangle(0, 0, loadedBm.Width, loadedBm.Height), GraphicsUnit.Pixel);
                }

                loadedBm.Dispose();

                return new Texture { TextureInformation = scaledBitmap };
            }
            else
                return new Texture { TextureInformation = loadedBm };
        }

        public ITexture GetTexture(string name)
        {
            var texture = LoadTexture(name);

            if (texture != null)
            {
                texture.Name = name;
                return texture;
            }

            texture = LoadTexture(String.Format("{0}.png", name));
            if (texture != null)
            {
                texture.Name = name;
                return texture;
            }

            texture = LoadTexture(String.Format("{0}.bmp", name));
            if (texture != null)
            {
                texture.Name = name;
                return texture;
            }

            throw new NullReferenceException(String.Format("Could not find asset with name: {0}, {0}.png,{0}.bmp.\r\n\r\nName of asset is case sensitive, also for consistency make sure your extensions is in lower case.", name));
        }

        public string ContentLocation { get; set; }

        public IAssetFactory AssetFactory
        {
            get;
            private set;
        }

        public IGameAudio LoadAudio(string name)
        {
            var audioAsset = AssetFactory.CreateAudioInstance();
            audioAsset.Load(this, name);

            return audioAsset;
        }

        public ISpriteImage LoadImage(string name)
        {
            var imageAsset = AssetFactory.CreateSpriteImage();
            imageAsset.Load(this, name);

            return imageAsset;
        }

        public void Dispose()
        {
            foreach (var bitmap in _assetLibrary.Values)
                bitmap.Dispose();
        }
    }
}
